package hibernate.method;

import hibernate.constraint.ErrorCodes;
import hibernate.method.interfaces.UserMethodsInterface;
import hibernate.model.Token;
import hibernate.model.User;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

public class UserMethods implements UserMethodsInterface {

	@Override
	public void add(SessionFactory sessionFactory, Session session,
			String username, String birthdate, String email, String type,
			String gender, String name, String surname, String phone,
			String password) {
		User u = new User();
		u.setUsername(username);
		u.setBirthdate(birthdate);
		u.setEmail(email);
		u.setAdd_date(AdditionalMethods.getCurrentDate());
		u.setType(type);
		u.setGender(gender);
		u.setName(name);
		u.setSurname(surname);
		u.setPhone(phone);
		u.setPassword(DigestUtils.md5Hex(password));
		u.setStatus("inactive");
		session.save(u);
	}

	@Override
	public void delete(SessionFactory sessionFactory, Session session, User u) {
		session.delete(u);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> list_by_type(SessionFactory sessionFactory,
			Session session, String type) {
		Criteria criteria = session.createCriteria(User.class);
		criteria.add(Restrictions.eq("type", type));
		return criteria.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> username_password(SessionFactory sessionFactory,
			Session session, String username, String password) {
		Criteria cr = session.createCriteria(User.class);

		Criterion username_cr = Restrictions.eq("username", username);
		Criterion password_cr = Restrictions.eq("password", DigestUtils.md5Hex(password));

		LogicalExpression andExp = Restrictions.and(username_cr, password_cr);
		cr.add(andExp);

		return cr.list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> list(SessionFactory sessionFactory, Session session) {
		Criteria cr = session.createCriteria(User.class);
		return cr.list();
	}

	@Override
	public User id_to_user(SessionFactory sessionFactory, Session session,
			int user_id) {
		User user = (User) session.get(User.class, new Integer(user_id));
		return user;
		// Object object = session.load(User.class, user_id);
		// User u = (User) object;
		// return u;
	}

	@Override
	public void edit_birthdate(SessionFactory sessionFactory, Session session,
			String birthdate, User u) {
		u.setBirthdate(birthdate);

	}

	@Override
	public void edit_email(SessionFactory sessionFactory, Session session,
			String email, User u) {
		u.setEmail(email);

	}

	@Override
	public void edit_gender(SessionFactory sessionFactory, Session session,
			String gender, User u) {
		u.setGender(gender);

	}

	@Override
	public void edit_name(SessionFactory sessionFactory, Session session,
			String name, User u) {
		u.setName(name);

	}

	@Override
	public void edit_surname(SessionFactory sessionFactory, Session session,
			String surname, User u) {
		u.setSurname(surname);

	}

	@Override
	public void edit_phone(SessionFactory sessionFactory, Session session,
			String phone, User u) {
		u.setPhone(phone);

	}

	@Override
	public void edit_password(SessionFactory sessionFactory, Session session,
			String password, User u) {
		u.setPassword(DigestUtils.md5Hex(password));
	}

	@Override
	public int sign_up_validation(SessionFactory sessionFactory,
			Session session, String username, String password) {
		List<User> is_user = is_user(sessionFactory, session, username);
		if (is_user == null || is_user.size() == 0)
			return ErrorCodes.IS_NOT_USER;
		else {
			User u = is_user.get(0);
			if (!u.getPassword().equals(DigestUtils.md5Hex(password)))
				return ErrorCodes.SIGN_UP_FAIL;
			else if (u.getStatus()=="inactive")
				return ErrorCodes.USER_INACTIVE;
			else {
				return u.getUser_id();
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<User> is_user(SessionFactory sessionFactory, Session session,
			String username) {
		Criteria cr = session.createCriteria(User.class);
		Criterion username_cr = Restrictions.eq("username", username);
		cr.add(username_cr);
		return cr.list();
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public List<String> used_emails(SessionFactory sessionFactory,
			Session session, String type) {
		Criteria criteria = session.createCriteria(User.class);
		criteria.add(Restrictions.eq("type", type));
		List<User> objects = criteria.list();
		List<String> emails = new ArrayList<String>();
		for (int i = 0; i < objects.size(); i++) {
			String single_email = objects.get(i).getEmail();
			emails.add(single_email);
		}
		return new ArrayList<String>(new HashSet(emails));
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public List<String> used_usernames(SessionFactory sessionFactory,
			Session session) {
		List<User> objects = list(sessionFactory, session);
		List<String> usernames = new ArrayList<String>();
		for (int i = 0; i < objects.size(); i++) {
			String username = objects.get(i).getEmail();
			usernames.add(username);
		}
		return new ArrayList<String>(new HashSet(usernames));
	}

	@Override
	public boolean isEmailExist(SessionFactory sessionFactory, Session session,
			String email, String type) {
		Criteria cr = session.createCriteria(User.class);

		cr.add(Restrictions.eq("email", email));
		cr.add(Restrictions.eq("type", type));
		if (cr.list() == null)
			return false;
		else
			return true;
	}

	@Override
	public String getUserType(SessionFactory sessionFactory, Session session,
			int user_id) {
		Criteria cr = session.createCriteria(User.class);
		cr.add(Restrictions.eq("user_id", user_id));
		User u = (User) cr.list().get(0);
		return u.getType();
	}

	@Override
	public int countClients(SessionFactory sessionFactory, Session session) {
			Criteria cr = session.createCriteria(User.class);
			cr.add(Restrictions.eq("type", "client"));
			return ((Number)cr.setProjection(Projections.rowCount()).uniqueResult()).intValue();
		}

	@Override
	public boolean isUsernameExist(SessionFactory sessionFactory,
			Session session, String username) {
		Criteria cr = session.createCriteria(User.class);

		cr.add(Restrictions.eq("username", username));
		if (cr.list().isEmpty())
			return false;
		else
			return true;
	}

	
	public static byte[] getUserAvatar (Connection conn, int user_id, String gender)
		       throws Exception, SQLException
		  {
		    String req = "" ;
		    Blob img ;
		    byte[] imgData = null ;
		    Statement stmt = conn.createStatement();
		
		    // Query
		    req = "Select avatar From usersavatars Where user_id = " + user_id ;
		    
		    ResultSet rset  = stmt.executeQuery ( req );   
		    
		    while (rset.next ())
		    {    
		      img = rset.getBlob(1);
		      imgData = img.getBytes(1,(int)img.length());
		    }    
		    
		    rset.close();
		    stmt.close();
		    
		    return imgData ;
		  }

	@SuppressWarnings("unchecked")
	@Override
	public List<User> listLatestRegisteredUsers(SessionFactory sessionFactory,
			Session session) {
		Criteria cr = session.createCriteria(User.class);
		cr.add(Restrictions.eq("add_date", maxDateRegister(sessionFactory, session)));
		cr.add(Restrictions.eq("type", "client"));
		cr.addOrder(Order.asc("username"));
		return cr.list();
	}

	@Override
	public String maxDateRegister(SessionFactory sessionFactory, Session session) {
		Criteria criteria = session
			    .createCriteria(User.class)
			    .setProjection(Projections.max("add_date")
			    );
		criteria.add(Restrictions.eq("type", "client"));
			return (String)criteria.uniqueResult();
	}

	@SuppressWarnings("rawtypes")
	@Override
	public int countUsersByAgeRange(SessionFactory sessionFactory,
			Session session, int beginAge, int endAge) {
		Query query = session.createSQLQuery(
				"select count(*) from users a where (type = :type and (floor(datediff(curdate(),birthdate)/ 365) > :beginAge) and (floor(datediff(curdate(),birthdate)/ 365)< :endAge)")
				.setParameter("type", "client")
				.setParameter("beginAge", beginAge)
				.setParameter("endAge", endAge);
				List result = query.list();
				return (Integer) result.get(0);
	}

	@Override
	public void insertToken(SessionFactory sessionFactory, Session session,
			String token, String operation, int user_id, String email) {
		Token t = new Token();
		t.setOperation(operation);
		t.setToken(token);
		t.setUser_id(user_id);
		t.setEmail(email);
		session.save(t);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Token> findTokenByOperationAndUser(
			SessionFactory sessionFactory, Session session, String operation,
			int user_id) {
		Criteria cr = session.createCriteria(Token.class);
		Criterion operationC = Restrictions.eq("operation", operation);
		Criterion userC = Restrictions.eq("user_id", user_id);
		LogicalExpression andExp = Restrictions.and(operationC, userC);
		cr.add(andExp);
		return cr.list();
	}

	@Override
	public void activateUser(SessionFactory sessionFactory, Session session,
			int user_id) {
		UserMethods um = new UserMethods();
		User u  = um.id_to_user(sessionFactory, session, user_id);
		u.setStatus("active");
	}


}